package main.mvc;

import static main.mvc.utils.BuildHelper.buildEntityName;
import static main.mvc.utils.BuildHelper.getImport;
import static main.mvc.utils.BuildHelper.getNAndT;
import static main.mvc.utils.BuildHelper.getPropertiesparse;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

import com.spring.annotation.entity.NotPersistent;
import com.spring.bean.example.Book;
import com.spring.utils.Constants;

public class DaoBuilder {
	
	public static void buildDao(String tableName, Class cls) {
		
		String tableNameUpp =  "TABLE_" + tableName.toUpperCase();
		String entityName = buildEntityName(tableName, true);
		String subName = buildEntityName(tableName, false);
		String tableNameStr = buildTableName(tableName);
		String columNames = getColumnStr(cls);
		/*
		 * package ...
		 * import java.util.List;
		 * import ....
		*/
		String headStr = buildHead(entityName);
		// public class BookDaoImpl extends DaoSupport implement BookDao {
		String daoStr = buildDaoStr(entityName);
		// private JdbcTemplate jdbcTemplate;
		String jdbcStr = buildJdbcTemplate();
		// insert(Entity entity){...}
		String insertStr = buildInsertStr(entityName, subName);
		// update(Entity entity){...}
		String updateStr = buildUpdateStr(entityName, subName);
		// delete(Entity entity){...}
		String deleteStr = buildDeleteStr(entityName, tableNameUpp);
		// getById(Integer id){...}
		String getByIdStr = buildGetByIdStr(entityName, tableNameUpp);
		// getList
		String getListStr = buildGetListStr(entityName, tableNameUpp, columNames);
		// getpage
		String getPageStr = buildQueryForPageStr(entityName, tableNameUpp, columNames);
		
	String _java = headStr + daoStr + jdbcStr + tableNameStr + insertStr + updateStr + deleteStr + getByIdStr + getListStr + getPageStr + "\n}";
//	System.out.println(_java);
		
		String folderName = getPropertiesparse().getValue("dao.impl.build.path");
		String fileName = getPropertiesparse().getValue("dao.impl.build.path") + File.separator + entityName + "DaoImpl.java";
		String isUpdate = getPropertiesparse().getValue("dao.impl.build.rebuild");
		
		try {
			File folder = new File(folderName);
			if(!folder.exists()){
				folder.mkdirs();
			}
			
			File file = new File(fileName);
			if(!file.exists()){
				file.createNewFile();
				BufferedWriter out = new BufferedWriter(new FileWriter(file));
				out.write(_java);
				out.close();
				System.out.println("dao is not exist");
			} else {
				if(isUpdate.equals("true")){
					file.delete();
					BufferedWriter out = new BufferedWriter(new FileWriter(file));
					out.write(_java);
					out.close();
				} 
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/** package ... import ... */
	public static String buildHead(String entityName) {
		StringBuffer head = new StringBuffer();
		head.append("package " + getPropertiesparse().getValue("dao.impl.build.package") + ";" + getNAndT(2, 0));
		head.append(getImport(1) + getNAndT(2, 0));
		
		head.append(getImport(11) + getNAndT(1, 0));
		head.append(getImport(12) + getNAndT(1, 0));
		head.append(getImport(13) + getNAndT(2, 0));
		
		head.append(getImport(2) + getNAndT(1, 0));
		head.append(getImport(6) + entityName + ";" + getNAndT(1, 0));
		head.append(getImport(8) + entityName + "Dao;" + getNAndT(1, 0));
		head.append(getImport(15) + getNAndT(1, 0));
		head.append(getImport(16) + getNAndT(1, 0));
		head.append(getImport(14) + getNAndT(2, 0));
		return head.toString();
	}
	
	/** public class XXXDao extends Dao {  */
	public static String buildDaoStr(String entityName) {
		return "@Repository" + getNAndT(1, 0) +  "public class " + entityName + "DaoImpl extends DaoSupport implements " + entityName+"Dao " + "{" + getNAndT(1, 0);
	}
	
	public static String buildJdbcTemplate(){
		return getNAndT(1, 1) + "@Autowired" + 
			   getNAndT(1, 1) +"private JdbcTemplate jdbcTemplate;";
	}
	
	/** tableName */
	public static String buildTableName (String tableName) {
		StringBuffer tableNameBuff = new StringBuffer();
		tableNameBuff.append(getNAndT(1, 1) + "private static final String TABLE_" + tableName.toUpperCase() + " = ");
		tableNameBuff.append("\"");
		tableNameBuff.append(tableName);
		tableNameBuff.append("\";");
		return 	tableNameBuff.toString();
	}
	
	/** public boolean insert(Entity entity) { ... } */
	public static String buildInsertStr(String entityName, String subName) {
		StringBuffer insertBuff = new StringBuffer();
		insertBuff.append(getNAndT(2, 1) + "/** insert */");
		insertBuff.append(getNAndT(1, 1) + "@Override");
		insertBuff.append(getNAndT(1, 1) + "public boolean insert(" + entityName + " " 
				+ subName + ") throws DaoException{");
		insertBuff.append(getNAndT(1, 2) + "try{");
		insertBuff.append(getNAndT(1, 3) + "return insert(jdbcTemplate, " + subName + ");");
		insertBuff.append(getNAndT(1, 2) + "} catch (Exception e) {");
		insertBuff.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- insert error : \" + e.getMessage());");
		insertBuff.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return insertBuff.toString();
	}

	/** public boolean update(Entity entity) { ... } */
	public static String buildUpdateStr(String entityName, String subName) {
		StringBuffer updateBuff = new StringBuffer();
		updateBuff.append(getNAndT(2, 1) + "/** udpate */");
		updateBuff.append(getNAndT(1, 1) + "@Override");
		updateBuff.append(getNAndT(1, 1) + "public boolean update(" + entityName + " " 
				+ subName + ") throws DaoException{");
		updateBuff.append(getNAndT(1, 2) + "try{");
		updateBuff.append(getNAndT(1, 3) + "return update(jdbcTemplate, " + subName + ");");
		updateBuff.append(getNAndT(1, 2) + "} catch (Exception e) {");
		updateBuff.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- update error : \" + e.getMessage());");
		updateBuff.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return updateBuff.toString();
	}
	
	/** public boolean detele(Entity entity) { ... } */
	public static String buildDeleteStr(String entityName, String tableName) {
		StringBuffer deleteBuff = new StringBuffer();
		deleteBuff.append(getNAndT(2, 1) + "/** delete */");
		deleteBuff.append(getNAndT(1, 1) + "@Override");
		deleteBuff.append(getNAndT(1, 1) + "public boolean delete(Integer id) throws DaoException{");
		deleteBuff.append(getNAndT(1, 2) + "try{");
		deleteBuff.append(getNAndT(1, 3) + "return deleteById(jdbcTemplate, " + tableName + ", id);");
		deleteBuff.append(getNAndT(1, 2) + "} catch (Exception e) {");
		deleteBuff.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- delete error : \" + e.getMessage());");
		deleteBuff.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return deleteBuff.toString();
	}
	
	/** public Entity getEntityById(Integer id) { ... } */
	public static String buildGetByIdStr(String entityName, String tableName) {
		StringBuffer getByIdBuff = new StringBuffer();
		getByIdBuff.append(getNAndT(2, 1) + "/** getEntityById */");
		getByIdBuff.append(getNAndT(1, 1) + "@Override");
		getByIdBuff.append(getNAndT(1, 1) + "public " + entityName + " getById(Integer id) throws DaoException{");
		getByIdBuff.append(getNAndT(1, 2) + "try{");
		getByIdBuff.append(getNAndT(1, 3) + "return getById(jdbcTemplate, "+ entityName + ".class , id);");
		getByIdBuff.append(getNAndT(1, 2) + "} catch (Exception e) {");
		getByIdBuff.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- query by id error : \" + e.getMessage());");
		getByIdBuff.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return getByIdBuff.toString();
	}
	
	/** public List<Entity> getEntityList(Integer id) { ... } */
	public static String buildGetListStr(String entityName, String tableName, String columNames) {
		StringBuffer getListBuff = new StringBuffer();
		getListBuff.append(getNAndT(2, 1) + "/** queryForList */");
		getListBuff.append(getNAndT(1, 1) + "@Override");
		getListBuff.append(getNAndT(1, 1) + "public List<" + entityName + "> queryForList() throws DaoException{");
		getListBuff.append(getNAndT(1, 2) + "String sql = \"select " + columNames + " from \" + " + tableName + ";");
		getListBuff.append(getNAndT(1, 2) + "try{");
		getListBuff.append(getNAndT(1, 3) + "return queryForList(jdbcTemplate, "+entityName + ".class, sql);");
		getListBuff.append(getNAndT(1, 2) + "} catch (Exception e) {");
		getListBuff.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- query list error : \" + e.getMessage());");
		getListBuff.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return getListBuff.toString();
	}
	
	public static String buildQueryForPageStr(String entityName, String tableName, String columNames) {
		StringBuffer pageBuffer = new StringBuffer();
		pageBuffer.append(getNAndT(2, 1) + "/** queryForPage */");
		pageBuffer.append(getNAndT(1, 1) + "@Override");
		pageBuffer.append(getNAndT(1, 1) + "public PageView<" + entityName + "> queryForPage(Page page) throws DaoException{");
		pageBuffer.append(getNAndT(1, 2) + "String sql = \"select " + Constants.SQL_PAGE_KEY + " " + columNames + " from \" + " + tableName + ";");
		pageBuffer.append(getNAndT(1, 2) + "try{");
		pageBuffer.append(getNAndT(1, 3) + "return queryForPage(jdbcTemplate, "+entityName + ".class, sql, page);");
		pageBuffer.append(getNAndT(1, 2) + "} catch (Exception e) {");
		pageBuffer.append(getNAndT(1, 3) + "throw new DaoException(\"" + entityName + " --- query page error : \" + e.getMessage());");
		pageBuffer.append(getNAndT(1, 2) + "}" + getNAndT(1, 1) + "}");
		return pageBuffer.toString();
	}
	
	public static <T> String getColumnStr(Class cls){
		Field[] fields = cls.getDeclaredFields();
		StringBuffer columStr = new StringBuffer();
		for(int i=0; i<fields.length; i++){
			if(fields[i].isAnnotationPresent(NotPersistent.class)){
				continue;
			}
			columStr.append(fields[i].getName() + ",");
		}
		return columStr.substring(0, columStr.length()-1).toString();
	}
	
	public static void main(String args[]){
		
		buildDao("book", Book.class);
		
	}
	
}
